<?php
#Express insert is a library that connects to an s3db deployment given an url, a key and a project_id and sorts  the order by which the collections items must be inserted.

#Include the Library to write S3QL queries


$url = 'http://ibl.mdanderson.org/s3dbdemo3/';
$key=  '6OhmdK6M5KNVScq';
$project_id = '2040';

list($CollectionOrder, $names) = sortByLessUsed($url,$key,$project_id);

echo "This is the order by which items should be inserted:";
echo '<pre>';print_r($CollectionOrder);
echo '<pre>';print_r($names);
exit;

function sortByLessUsed($url,$key,$project_id)
	{
    list($rules, $collections,$collection_names) =s3db_retrieve_rules($url,$key,$project_id);
	
	#Create a transition matrix of all collections where the rows are the collections that depend and the cols the collections that are dependend on
	$M = array_zeros(count($collections));
	
	foreach ($rules as $ruleID=>$tmp) {
	$ind['sub'] = array_search($tmp['subject_id'], $collections);

	if($tmp['object_id'])
		{  	
			$ind['obj'] = array_search($tmp['object_id'],$collections);
			$M[$ind['sub']][$ind['obj']]=1;
		}

	}
	
	$it=1;$order=array();
	
	#Repeat removeZeroCountLines until all the rows sum is zero or when the number of iterations is larger than the number of collections (nodes)
	while (count($order)<count($collections) && $it<count($collections)) {
		list($M, $order) = removeZeroCountLines($M, $collections,$order, $it);	
	
		$it++;
	
	}
	
	
	foreach ($order as $Cid=>$ord) {
		$names[$Cid] = $collection_names[$Cid];
	} 
	
	 return (array($order, $names));


	}


function removeZeroCountLines($M, $collections, $order, $it)
{
#1. Sum all the rows, create all the collections which sum amount to zero;
for ($i=0; $i < count($M); $i++) {
	$C[$i] = array_sum($M[$i]);
	
	
	if($C[$i]==0 && !in_array($collections[$i], array_keys($order)))
	{	
		$order[$collections[$i]]=$it;
		$deadRows[] = $i;
		
		
	}
	
}

#2.Take the columns of the rows that resulted in the previous result, for example, 5 and 6, and zero-out those columns - that is, tranform all values into zero.
for ($row=0; $row < count($M); $row++) {
	if(is_array($deadRows))
	for ($col=0; $col <count($M[$row]) ; $col++) {
		if(in_array($col, $deadRows))
			{
			$M[$row][$col]=0;
			}
	}
}

return (array($M, $order));
}

function array_zeros($x, $y='x')
{
	if($y=='x')
		$y=$x;
	
	$Z = array_fill(0, $x, 0);
	
	foreach ($Z as $zRow) {
		$Zi[] =array_fill(0, $y, 0);
	}
	return ($Zi);
}

function s3db_retrieve_rules($url,$key,$project_id){
	$cache = 'serialized_rules'.md5($url.$key.$project_id.date('Ymd'));
	if(is_file($cache))
	{
		$data = load($cache);
	}
	else{

	$s3ql=array('url'=>$url,'key'=>$key, 'from'=>'rules','where'=>array('project_id'=>$project_id));
	
	$data = S3DBCall($s3ql);
	
	$data = $data[1];
	save($cache, $data, $t='w');
	}
	
	
	
	foreach ($data as $rule_data) {
		$rules[$rule_data['rule_id']] = $rule_data;
		$collection_names[$rule_data['subject_id']] = $rule_data['subject'];
		if($rule_data['object_id'])
		$collection_names[$rule_data['object_id']] = $rule_data['object'];
		$collections[] = $rule_data['subject_id'];
		

	}
	 $collections = array_values(array_unique($collections));
	 
	
	return (array($rules, $collections, $collection_names));

	}
function load($file)
	{
	$dF = fopen($file,'r');
	
	$info = fread($dF, filesize($file));
	$info = unserialize($info);	
	return ($info);
	}

function save($file, $data, $t='w')
	{
	$dF = fopen($file,'w');
	
	$info = serialize($data);
	fwrite($dF, $info);
	fclose($dF);
	chmod($file,0777);
	}
function S3DBcall($s3ql)
{#S3DBcall takes in an array formatted in S3QL terms (for exmaple, $s3ql = array('url','http://ibl.mdanderson.org/s3db','key','xxxxxx','select','*','from','projects');)
#and return the output from s3db parsed in an array
if($s3ql['format']!='php') $s3ql['format']='php';
$url = S3QLquery($s3ql);
#echo $url;
$h = fopen($url,'r');
while(!$h){
	$h = fopen($url,'r');
}
$data = stream_get_contents($h);
return (array($url,unserialize($data)));
	
}
function S3QLquery($s3ql)

	{
	#Function S3QLquery builds the S3QL query for any remote uri
	#INPUT: $s3ql is an array with at least key
	#OUTPUT: a string, containing the URI with the information on the input element UID 
	#Helena F Deus

	if($s3ql['url']=='')
	if ($_SERVER['HTTP_X_FORWARDED_HOST'] != '') 
		$s3ql['url'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
	else $s3ql['url'] = $_SERVER['HTTP_HOST'];


	$wrap .= $s3ql['url'].'/S3QL.php';
	
	if ($s3ql['user_id']!='') {
		$wrap .= '?user_id='.$s3ql['user_id'];
	}
	if ($s3ql['format']!='') {
		$wrap .= (($s3ql['user_id']!='')?'&':'?').'format='.$s3ql['format'];
			
	}
	
	$wrap .= (($s3ql['user_id']=='' && $s3ql['format']=='')?'?':'&').'query=<S3QL>';
	$wrap .= '<key>'.$s3ql['key'].'</key>';

	#remove the elements already used to build the query, keep the rest
	$s3ql = array_diff_key($s3ql, array('url'=>'', 'key'=>'', 'db'=>'','user_id'=>'','format'=>''));

	foreach($s3ql as $field=>$value)
		{
		if(!is_array($s3ql[$field])) #if is not an array, just build the simple xml
		$wrap .= '<'.$field.'>'.$s3ql[$field].'</'.$field.'>';
		else #for arrays, build the nested xml
		{$wrap .= '<'.$field.'>';
		foreach($value as $subfield=>$subvalue)
			{
			$wrap .= '<'.$subfield.'>'.$subvalue.'</'.$subfield.'>';
			}
		$wrap .= '</'.$field.'>';
		}
		}
	$wrap .= '</S3QL>';
	
	


	return $wrap;
	}
?>
